package com.tsfyun.scm.gateway.handler;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.tsfyun.scm.gateway.config.properties.NoticeProperties;
import com.tsfyun.scm.gateway.support.dd.DingTalkNoticeUtil;
import com.tsfyun.scm.gateway.util.IpUtils;
import com.tsfyun.scm.gateway.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

@Slf4j
public class GatewayExceptionHandler extends DefaultErrorWebExceptionHandler {

	@Autowired
	private NoticeProperties noticeProperties;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Value("${gateway.ipcheck.limit:1440}")
	private long blackIpLimit;

	private AntPathMatcher pathMatcher = new AntPathMatcher();

	private static List<String> noNotice = new ArrayList<String>(){{
		add("/scm/taskNotice/count");
		add("/websocket");
	}};

	private static List<String> crawlKeywords = new ArrayList<String>(){{
		add("sitemap.xml");
		add("atom.xml");
		add("sitemaps.xml");
		add("sitemaps.xml.gz");
		add("sitemap_index.xml");
		add("sitemap.xml.gz");
		add("sitemaps_index.xml");
	}};

	@Value("${spring.profiles.active:dev}")
	private String profiles;

	public GatewayExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
								   ErrorProperties errorProperties, ApplicationContext applicationContext) {
		super(errorAttributes, resourceProperties, errorProperties, applicationContext);
	}

	/**
	 * 获取异常属性
	 */
	@Override
	protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
		String code = "0";
		String errorMessage = Result.DEFAULT_ERROR_MSG;
		Map<String, Object> map = new HashMap<>();
		map.put("code", code);
		Throwable error = super.getError(request);
		log.error(String.format("网关异常，请求地址：%s",request.exchange().getRequest().getURI()),error);
		if (error instanceof org.springframework.cloud.gateway.support.NotFoundException) {

		}
		map.put("message", errorMessage);
		//此处自主增加白名单
		long includeCrawl = crawlKeywords.stream().filter(r-> request.exchange().getRequest().getPath().value().contains(r)).count();
		if(includeCrawl > 0) {
			String ip =  IpUtils.getIpAddress(request.exchange().getRequest());
			stringRedisTemplate.opsForValue().set("BLACK_IP:" + ip, "1", blackIpLimit, TimeUnit.MINUTES);
		}
		//此处钉钉通知
		Boolean isNotice = noNotice.stream().filter(url->pathMatcher.match(url,request.exchange().getRequest().getPath().value())).count() <= 0;
		if(isNotice && includeCrawl <= 0) {
			DingTalkNoticeUtil.send2DingDingException(request.exchange().getRequest(),"请求异常",error,noticeProperties.getDingdingUrl(),profiles);
		}
		return map;
	}

	/**
	 * 指定响应处理方法为JSON处理的方法
	 * @param errorAttributes
	 */
	@Override
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
	}

	/**
	 * 根据code获取对应的HttpStatus
	 * @param errorAttributes
	 * @return
	 */
	@Override
	protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
		return HttpStatus.OK;
	}

}

